/*******************************************************************************
 * Copyright (c) 2011 Technische Universität Darmstadt
 * 					  Fachbereich Informatik
 * 					  Theoretische Informatik - Kryptographie und Computeralgebra
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

//info.version returns version of TB!
var info = Components.classes["@mozilla.org/xre/app-info;1"]
.getService(Components.interfaces.nsIXULAppInfo);

if(info.version.charAt(0)<5){
	Components.utils.import("resource://app/modules/errUtils.js"); // not comp w TB5
	Components.utils.import("resource://app/modules/gloda/utils.js"); //not tb5
	Components.utils.import("resource://app/modules/gloda/gloda.js"); //not tb5
}
Components.utils.import("resource://gre/modules/iteratorUtils.jsm");
Components.utils.import("resource:///modules/MailUtils.js");
Components.utils.import("resource:///modules/gloda/mimemsg.js");
Components.utils.import("resource:///modules/gloda/noun_mimetype.js");

if(info.version.charAt(0)>=5){
	Components.utils.import("resource://gre/modules/AddonManager.jsm"); //needed!
	Components.utils.import("resource://gre/modules/Services.jsm");
}

/**
 *	Instance TheChasingDragon of class cryptoBird.
 *	The overall class for this extension.
 *	Load this class on ThunderBird start.
 */
var TheChasingDragon = null;
var debug = false;
var extensionPath ='NOT_SET';
var addonID = "CryptoBird@cdc.de";
var stringBundlef;

window.addEventListener("load", function(){
	stringBundlef = document.getElementById("cryptoBirdStringBundle");
	if(extensionPath == 'NOT_SET'){
		if(info.version.charAt(0)<5){
			extensionPath = Components.classes["@mozilla.org/extensions/manager;1"].
			getService(Components.interfaces.nsIExtensionManager).
			getInstallLocation(addonID). // guid of extension
			getItemLocation(addonID);
			loadcryptoBird();
		}else{
			//for TB5:
			AddonManager.getAddonByID(addonID, function(addon) {
				extensionPath = addon.getResourceURI("").QueryInterface(Components.interfaces.nsIFileURL).file;
				loadcryptoBird();
			});
		}
	}
}, false);

function loadcryptoBird(){
	// only do this if we have not loaded that class.
	// Only in the main window. So not on the wizard
	if (!TheChasingDragon && window.name != "CryptoBird") {
		TheChasingDragon = new cryptoBird(true);
		// start java etc.
		if(TheChasingDragon && !TheChasingDragon.loaded) {
			TheChasingDragon.loaded = true;
			TheChasingDragon.cryptoBird_onload();
		}
		// add a first listener to folders (to add new listener on new folder)
		FolderDisplayListenerManager.registerListener(TheChasingDragon.dbListener);

		// add a second folder listener (to get move/copy events)
		var notificationService = Components.classes["@mozilla.org/messenger/msgnotificationservice;1"].getService(Components.interfaces.nsIMsgFolderNotificationService);
		notificationService.addListener(TheChasingDragon.folderListener, 	notificationService.msgAdded |
				notificationService.msgsDeleted |
				notificationService.msgsMoveCopyCompleted |
				notificationService.folderRenamed |
				notificationService.folderMoveCopyCompleted |
				notificationService.folderDeleted |
				notificationService.itemEvent);

		// add uninstall listener // NOTE: only for Gecko 1.9. Has changed to AddonManager for Gecko 2.0!
		// also install listener -> ask for preferences and start indexing
		if(info.version.charAt(0)<5){
			Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService).addObserver(TheChasingDragon.UninstallListener, "em-action-requested", false);
		}else{
			let listener = {
					onUninstalling: function(addon)
					{
						if (addon.id == addonID)
						{
							TheChasingDragon.UninstallListener.observe(addonID,"em-action-requested","item-uninstalled");
						}
					}
			}

			AddonManager.addAddonListener(listener);
		}	
	}
}

/**
 *	Utility function to check if it is the first run of this extension.
 */
function firstRun(guid, del){
	var bfirstrun;
	if(info.version.charAt(0)<5){
		bfirstrun = navigator.preference( guid +'.first_run');
	}else{ //if preference is not found an exception is thrown
		try{
			bfirstrun = Services.prefs.getBoolPref(guid +'.first_run');
		}catch(e){
			bfirstrun =false;
		}
	}


	if (bfirstrun && del) {
		// remove preference so other windows don't see it before next restart
		if(info.version.charAt(0)<5){
			Components.classes["@mozilla.org/preferences-service;1"]
			.getService(Components.interfaces.nsIPrefBranch)
			.deleteBranch (guid +'.first_run');
		}else{
			Services.prefs.deleteBranch(guid +'.first_run');
		}
		// remove preference file so pref doesn't get loaded on next restart
		var file = extensionPath;
		file.append("defaults");
		file.append("preferences");
		file.append("first_run.js"); // first_run.js default preference file
		file.remove(false);
		return true;
	} else
		return false;
}


/**
 *	"install wizard"
 */
window.addEventListener("load", function(){
	if(extensionPath == 'NOT_SET'){
		if(info.version.charAt(0)<5){
			extensionPath = Components.classes["@mozilla.org/extensions/manager;1"].
			getService(Components.interfaces.nsIExtensionManager).
			getInstallLocation(addonID). // guid of extension
			getItemLocation(addonID);
			if (firstRun("cryptoBird", true)) {
				window.open("chrome://CryptoBird/content/installWizard.xul", "CryptoBird", "chrome,width=700,height=450");
			}
		}else{
			//for TB5:
			AddonManager.getAddonByID(addonID, function(addon) {
				extensionPath = addon.getResourceURI("").QueryInterface(Components.interfaces.nsIFileURL).file;
				if (firstRun("cryptoBird", true)) {
					window.open("chrome://CryptoBird/content/installWizard.xul", "CryptoBird", "chrome,width=700,height=450");
				}
			});
		}
	}else{
		if (firstRun("cryptoBird", true)) {
			window.open("chrome://CryptoBird/content/installWizard.xul", "CryptoBird", "chrome,width=700,height=450");
		}	
	}
}, false);

/**
 * improves usability of re-installation during wizard
 */
function enterValues(){
	var guid = "cryptoBird";
	var pgppath = "";
	var skfile = "secring.gpg";
	var pkfile = "pubring.gpg";
	if(info.version.charAt(0)<5){
		pgppath = navigator.preference( guid +'.pgp_path'); 
		skfile = navigator.preference( guid +'.pgp_sk_name');
		pkfile = navigator.preference( guid +'.pgp_pk_name');
	}else{	
		try{
			pgppath = Services.prefs.getCharPref( guid +'.pgp_path');
			skfile = Services.prefs.getCharPref( guid +'.pgp_sk_name');
			pkfile = Services.prefs.getCharPref( guid +'.pgp_pk_name');

		}catch(e){

		}
	}
	document.getElementById('textpgppath').value = pgppath;
	if(pkfile != '')document.getElementById('textpgppkname').value = pkfile;
	if(skfile != '')document.getElementById('textpgpskname').value = skfile;
}


/**
 *	The Main Class.
 *	Everything is done here.
 */
function cryptoBird() {
	// The search string
	this.search_value;
	// True if the extension has been enabled through button
	this.cryptoBirdEnabled = false;
	// Java Object for PGP decryption
	this.cryptoBirdJava;
	// Toggle if Java has been loaded (don't need to load it twice!)
	this.loaded;
	// The list with the search results
	this.list;
	// Boolean if we leave a folder to unregister the listener there
	this.leavedFolder;
	// Decides if this extension is enabled
	this.disabled = false;
	// nsIActivityManager to inform user about indexing progress
	this.gActivityManager = Components.classes["@mozilla.org/activity-manager;1"].getService(Components.interfaces.nsIActivityManager);
	// The process for the activity manager
	this.process = Components.classes["@mozilla.org/activity-process;1"].createInstance(Components.interfaces.nsIActivityProcess);
	// List of incoming messages
	this.incomingMessages = new Array();

	/*** Preferences Service: gets the preferences specified in file options.xul ***/
	// Get the prefBranch, here cryptoBird.
	this.prefBranch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch ("cryptoBird.");

	/*
	 *	Listening on folder change to register searchListener on new folder.
	 *	Implements IDBViewWrapperListener
	 */
	this.dbListener = {
			onDisplayingFolder : function()	{	if (TheChasingDragon.cryptoBirdEnabled) {
				document.getElementById("tabmail").currentTabInfo.folderDisplay.view.search.session.registerListener(TheChasingDragon.searchListener);
			}
			},
			onLeavingFolder : function(){ if (TheChasingDragon.leavedFolder) {
				TheChasingDragon.leavedFolder.unregisterListener(TheChasingDragon.searchListener);
			}
			},
	}

	/*
	 *	Listener for uninstall notification
	 *	As quit-application is not working we ask here if we should drop the DB and perform action immediately
	 */
	this.UninstallListener = {
			observe: function(subject, topic, data) {
				// subject: [xpconnect wrapped nsISupports], topic: em-action-requested, data: item-uninstalled -> uninstall
				if (topic == "em-action-requested" && data == "item-uninstalled"){
					var correctId = true;
					if(info.version.charAt(0)<5){
						subject.QueryInterface(Components.interfaces.nsIUpdateItem);
						if(subject.id != addonID)
							correctId = false;
					}
					if(correctId){
						var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
						var check = {value : false};
						//prompt.alertCheck(null, "Uninstall CryptoBird", "To uninstall CryptoBird Thunderbird will exit now. You need to start it again manually.","Delete the entire database. Not recommended if you want to reinstall CryptoBird.", check);
						prompt.alertCheck(null, stringBundlef.getString("cryptoBird.main.uninstall"), stringBundlef.getString("cryptoBird.main.uninstallmessage"),stringBundlef.getString("cryptoBird.main.uninstallDB"), check);

						if(check.value){
							//remove db pw:
							var loginManager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager);
							if(loginManager.countLogins('chrome://cryptobird','','cryptobird_db_pw') > 0){
								var logins = loginManager.findLogins({}, "chrome://cryptobird", null, 'cryptobird_db_pw');
								for (var i = 0; i < logins.length; i++) {
									if (logins[i].username == 'db') {
										loginManager.removeLogin(logins[i]);
										break;
									}
								}
							}

							TheChasingDragon.cryptoBirdJava.removeDB();
							subject.data = true;

						}
						Components.classes['@mozilla.org/toolkit/app-startup;1'].getService(Components.interfaces.nsIAppStartup).quit(Components.interfaces.nsIAppStartup.eAttemptQuit);	

					}
				}
			}
	}

	/**
	 *	Process the wizard finished event:
	 *	- Set Preferences
	 *	- Start Indexing
	 */
	this.wizardFinished = function wizardFinished(window, textpgppath, textpgppkname, textpgpskname, startIndexing){
		// set preferences
		window.close;
		TheChasingDragon.prefBranch.setCharPref("pgp_path", textpgppath);
		TheChasingDragon.prefBranch.setCharPref("pgp_sk_name", textpgpskname);
		TheChasingDragon.prefBranch.setCharPref("pgp_pk_name", textpgppkname);

		TheChasingDragon.cryptoBirdJava.setPGPPath(textpgppath, textpgpskname, textpgppkname);
		
		// start indexing if wished
		if (startIndexing){
			TheChasingDragon.queryTheChasingDragon();
		}
	}

	/**
	 *	Testing function to display a message to an URI
	 */
	this.testUri = function testUri(){
		var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
		var password = {value: ""};              				
		var check = {value: true};                   		// default the checkbox to true
		var result = promptService.prompt(null, "..::TEST::..", "mail: ", password, null, check);
		var pwvalue = password.value;
		let messenger = Components.classes["@mozilla.org/messenger;1"].createInstance(Components.interfaces.nsIMessenger); 
		var foundMsgHdr = messenger.msgHdrFromURI(pwvalue);
		MailUtils.displayMessage(foundMsgHdr);
	};

	/**
	 *	Enable / Disable this search
	 */
	this.toggleChasingDragon = function toggleChasingDragon() {
		// only do something if the extension itself is enabled

		if (!TheChasingDragon.disabled) {
			this.cryptoBirdEnabled = document.getElementById("cryptoBird-toggle").hasAttribute("checked");
			if (this.cryptoBirdEnabled){

				// load java etc. if not done yet
				if(!this.loaded) {
					this.cryptoBird_onload();
				}

				leavedFolder = document.getElementById("tabmail").currentTabInfo.folderDisplay.view.search.session;

				// add search listener for quickfilter
				document.getElementById("tabmail").currentTabInfo.folderDisplay.view.search.session.registerListener(TheChasingDragon.searchListener);
				// search! (if there is something in the search box)

				if (document.getElementById("qfb-qs-textbox").value) {
					//document.getElementById("tabmail").currentTabInfo.folderDisplay.view.search.session.search(msgWindow);
					this.refreshQuickSearch();
				}
			} else { // cryptoBird is not enabled
				// remove search listener for quickfilter
				document.getElementById("tabmail").currentTabInfo.folderDisplay.view.search.session.unregisterListener(TheChasingDragon.searchListener);
				if (document.getElementById("qfb-qs-textbox").value)
					this.refreshQuickSearch();
			}
		}
	};


	/*
	 * Refresh QuickSearch (workaround because quicksearch does only respond to user input so we send key events
	 */

	this.refreshQuickSearch = function refreshQuickSearch(){
		TheChasingDragon.sendKeyEvent(32);
		window.setTimeout("TheChasingDragon.sendKeyEvent(8)", 501);
	}

	/*
	 * helper for refreshQuickSearch
	 */

	this.sendKeyEvent = function sendKeyEvent(c){
		var e = document.createEvent("KeyboardEvent");
		e.initKeyEvent('keypress', true, true, null, false, false, false, false, c, c);

		var obj = document.getElementById("qfb-qs-textbox");
		obj.inputField.dispatchEvent(e);
	}


	/**
	 *	Set up the folder listener to point to the function above
	 */
	this.folderListener = {
			msgAdded: function(aMsgHdr) {	var msgURI = aMsgHdr.folder.getUriForMsg(aMsgHdr);
											TheChasingDragon.incomingMessages.push(msgURI);
											TheChasingDragon.parse_online_mail();
			},
			msgsDeleted: function(items)	{	for (var i = 0; i < items.length; i++) {
													var itemHdr = items.queryElementAt(i, Components.interfaces.nsIMsgDBHdr);
													var msgURI = itemHdr.folder.getUriForMsg(itemHdr);
													TheChasingDragon.cryptoBirdJava.removeMail(msgURI);
												};
			},
			msgsMoveCopyCompleted : function(move, items, destfolder, aDestMsgs) {
				for ( var i = 0; i < items.length; i++) {
					var itemHdr = items.queryElementAt(i,
							Components.interfaces.nsIMsgDBHdr);
					var msgURI = itemHdr.folder.getUriForMsg(itemHdr);
					if (aDestMsgs == null) { // it's on the server (imap) -> can
						// not move it, so delete it. It
						// will trigger msgAdded
						if (move) {
							TheChasingDragon.cryptoBirdJava.removeMail(msgURI);
						} else {
							// nothing to do here since it is a copy and we are in a
							// smime folder, so msgAdded will be called later
						}
					} else {
						var itemHdrDest = aDestMsgs.queryElementAt(i,
								Components.interfaces.nsIMsgDBHdr);
						var msgURIDest = itemHdrDest.folder
						.getUriForMsg(itemHdrDest);
						if (move) {
							TheChasingDragon.cryptoBirdJava.changeId(msgURI,
									msgURIDest);
						} else {
							TheChasingDragon.cryptoBirdJava.addCopiedId(msgURI,
									msgURIDest);
						}
					}
				}
				;
			},
			folderMoveCopyCompleted : function(aMove, aSrcFolder, aDestFolder) {
				if (aMove) {
					TheChasingDragon.cryptoBirdJava.changeFolder(
							aSrcFolder.baseMessageURI, aDestFolder.baseMessageURI);
				} else {
					TheChasingDragon.cryptoBirdJava.copyFolder(
							aSrcFolder.baseMessageURI, aDestFolder.baseMessageURI);
				}
			},
			folderRenamed : function(aOrigFolder, newFolder) {
				TheChasingDragon.cryptoBirdJava.changeFolder(
						aOrigFolder.baseMessageURI, newFolder.baseMessageURI);
			}, 
			folderDeleted: function(aFolder) {TheChasingDragon.cryptoBirdJava.removeFolder(aFolder.baseMessageURI);},
	};

	this.downloadedFolders = Components.classes["@mozilla.org/array;1"].createInstance(Components.interfaces.nsIMutableArray);
	
	this.parse_online_mail = function parse_online_mail(){
		this.mailAdded = true;
		window.setTimeout("TheChasingDragon.imapHelp()", 2000);

	};
	
	function findAccountFromFolder(theFolder) {
		if (!theFolder)
			return null;
		var acctMgr = Components.classes["@mozilla.org/messenger/account-manager;1"].getService(Components.interfaces.nsIMsgAccountManager);
		var accounts = acctMgr.accounts;
		for (var i = 0; i < accounts.Count(); i++) {
			var account = accounts.QueryElementAt(i, Components.interfaces.nsIMsgAccount);
			var rootFolder = account.incomingServer.rootFolder; // nsIMsgFolder
			if (rootFolder.hasSubFolders) {
				var subFolders = rootFolder.subFolders; // nsIMsgFolder
				while(subFolders.hasMoreElements()) {
					if (theFolder == subFolders.getNext().QueryInterface(Components.interfaces.nsIMsgFolder))
						return account.QueryInterface(Components.interfaces.nsIMsgAccount);
				}
			}
		}
		return null;
	}

	this.mailAdded = false;

	this.imapHelp = function(){
		if(this.mailAdded){
			this.mailAdded = false;
			let messenger = Components.classes["@mozilla.org/messenger;1"].createInstance(Components.interfaces.nsIMessenger);
			while ( TheChasingDragon.incomingMessages.length > 0) {
				var msgUri = TheChasingDragon.incomingMessages[0];
				var msgHdr = messenger.msgHdrFromURI(msgUri);
				TheChasingDragon.parse_encrypted_mail(msgHdr, false);
				TheChasingDragon.incomingMessages.pop();
			}
		}
	}

	/**
	 *	Utility function to as for a password
	 */
	this.getPWD = function getPWD(){
		var loginManager = Components.classes["@mozilla.org/login-manager;1"]
		.getService(Components.interfaces.nsILoginManager);
		var loginInfo = Components.classes["@mozilla.org/login-manager/loginInfo;1"]
		.createInstance(Components.interfaces.nsILoginInfo);

		if(loginManager.countLogins('chrome://cryptobird','','cryptobird_db_pw') == 0){
			var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			var password = {value: ""};        
			var check = {value: true};                   		
			var result = promptService.promptPassword(null, stringBundlef.getString("cryptoBird.main.DBPW"), stringBundlef.getString("cryptoBird.main.DBPWmessage"), password, null, check);
			password = password.value;
			loginInfo.init('chrome://cryptobird', null, 'cryptobird_db_pw', 'db', password, "", "");

			loginManager.addLogin(loginInfo);
		}else{
			//take first pw (?)
			var logins = loginManager.findLogins({}, "chrome://cryptobird", null, 'cryptobird_db_pw');
			for (var i = 0; i < logins.length; i++) {
				if (logins[i].username == 'db') {
					password = logins[i].password;
					break;
				}
			}
		}


		return password;
	};

	/**
	 *	Called on startup to get db password and start java
	 */
	this.cryptoBird_onload = function cryptoBird_onload() {
		/*
		 *	Prompt for PGP password
		 */
		var loginManager = Components.classes["@mozilla.org/login-manager;1"]
		.getService(Components.interfaces.nsILoginManager);
		var loginInfo = Components.classes["@mozilla.org/login-manager/loginInfo;1"]
		.createInstance(Components.interfaces.nsILoginInfo);
		var logins;
		if (debug) alert('Starting login procedure');
		if(loginManager.countLogins('chrome://cryptobird','','cryptobird_db_pw') == 0){
			if (debug) alert('No Logins saved');
			var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			var password = {value: ""};        
			var check = {value: true};                   		
			var result = promptService.promptPassword(null, stringBundlef.getString("cryptoBird.main.DBPW"), stringBundlef.getString("cryptoBird.main.DBPWmessage"), password, stringBundlef.getString("cryptoBird.main.DBPWnotask"), check);
			//var result = promptService.promptPassword(null, "Database password required", "Please enter the CryptoBird password:", password, "Store password and do not ask me again", check);
			password = password.value;
			if(check.value){
				loginInfo.init('chrome://cryptobird', null, 'cryptobird_db_pw', 'db', password, "", "");
				loginManager.addLogin(loginInfo);
				if (debug) alert('Login added to DB');
			}
		}else{
			if (debug) alert('Found Login');
			//look for pw
			logins = loginManager.findLogins({}, "chrome://cryptobird", null, 'cryptobird_db_pw');
			for (var i = 0; i < logins.length; i++) {
				if (logins[i].username == 'db') {
					password = logins[i].password;
					result = true;
					if (debug) alert('Password was found');
					break;
				}
			}
		}
		// check if the password is long enough (needed for derby db, but also for security reasons ;)
		while (password.length < 8 && result) {
			if (debug) alert('pw too short');
			var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			prompt.alert(null, stringBundlef.getString("cryptoBird.main.PWshort"), stringBundlef.getString("cryptoBird.main.PWshortmessage"));
			var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			var password = {value: ""};              				
			var check = {value: true};                   	
			var result = promptService.promptPassword(null, stringBundlef.getString("cryptoBird.main.DBPW"), stringBundlef.getString("cryptoBird.main.DBPWmessage"), password, stringBundlef.getString("cryptoBird.main.DBPWnotask"), check);
			password = password.value;
			if(check.value){
				if(loginManager.countLogins('chrome://cryptobird','','cryptobird_db_pw') == 0){
					loginInfo.init('chrome://cryptobird', null, 'cryptobird_db_pw', 'db', password, "", "");
					loginManager.addLogin(loginInfo);
				}else{
					loginInfo.init('chrome://cryptobird', null, 'cryptobird_db_pw', 'db', password, "", "");
					logins = loginManager.findLogins({}, "chrome://cryptobird", null, 'cryptobird_db_pw');
					for (var i = 0; i < logins.length; i++) {
						if (logins[i].username == 'db') {
							loginManager.modifyLogin(logins[i], loginInfo);
							break;
						}
					}
				}	
			}else{ //Password could be set in first place, so delete it again:
				if(loginManager.countLogins('chrome://cryptobird','','cryptobird_db_pw') > 0){
					logins = loginManager.findLogins({}, "chrome://cryptobird", null, 'cryptobird_db_pw');
					//	loginManager.findLogins({}, "chrome://cryptobird", '', 'cryptobird_db_pw', logins);
					for (var i = 0; i < logins.length; i++) {
						if (logins[i].username == 'db') {
							loginManager.removeLogin(logins[i]);
							break;
						}
					}

				}
			}
		}
		if(debug) alert('result: ' + password);
		if (result){

			/*
			 *	Read the environment variables for java encryption
			 */
			var pgpPath = safeGetCharPref(TheChasingDragon.prefBranch, "pgp_path");
			var pgpSKName = safeGetCharPref(TheChasingDragon.prefBranch, "pgp_sk_name");
			var pgpPKName = safeGetCharPref(TheChasingDragon.prefBranch, "pgp_pk_name");

			/*
			 *	List for search results
			 */ 
			TheChasingDragon.list = Components.classes["@mozilla.org/array;1"].createInstance(Components.interfaces.nsIMutableArray);

			/*
			 *	Start JAVA stuff
			 */
			if(debug) alert('initialize java');
			this.startJava(pgpPath, pgpSKName, pgpPKName, password);

			// TODO: perhaps listening on enter to change to global search?

			this.loaded = true;
		}
	};

	/**
	 *	Iterate through all folders and parse the mails for encrypted mails
	 */
	this.iterateFolders = function iterateFolders(rootFolder, percentage, accountName) {
		if (rootFolder.hasSubFolders) {
			var result = true;
			var subFolders = rootFolder.subFolders; // nsIMsgFolder
			while (subFolders.hasMoreElements()) {
				var folder = subFolders.getNext().QueryInterface(Components.interfaces.nsIMsgFolder);
				Application.console.log("--------"+folder.prettiestName);
				TheChasingDragon.process.setProgress(Math.round(percentage * 10) / 10+"% - "+stringBundlef.getString("cryptoBird.main.activityindex")+ " "+accountName+" - "+folder.prettiestName+"... ", stringBundlef.getString("cryptoBird.main.activityindex")+" "+folder.prettiestName, 0, 100);
				try {
					var folderMessages = folder.messages;
					while (folderMessages.hasMoreElements()) {
						var msgHdr = folderMessages.getNext().QueryInterface(Components.interfaces.nsIMsgDBHdr);
						result = true;
						result = TheChasingDragon.parse_encrypted_mail(msgHdr, true);
						if (!result)
							break;
					}
				} catch (e) {
					Application.console.log("iterateFolders: "+e);
				}
				if (result)
					iterateFolders(folder, percentage, accountName);
				else
					return false;
			}
		}
		return true;
	};


	/*
	 *	Start indexing the mail database and store all found mails in our
	 *	own db.
	 */
	this.queryTheChasingDragon = function queryTheChasingDragon() {
		if (!TheChasingDragon.disabled) {
			if(!this.loaded) {
				alert("load in queryTheChasingDragon");
				this.cryptoBird_onload();
			}
			// reset database
			TheChasingDragon.cryptoBirdJava.resetDatabase();

			// start activity manager
			TheChasingDragon.process.init(stringBundlef.getString("cryptoBird.main.activitystartindex"), null);
			TheChasingDragon.gActivityManager.addActivity(TheChasingDragon.process);

			// go through folders and add encrypted mails to database
			var acctMgr = Components.classes["@mozilla.org/messenger/account-manager;1"].getService(Components.interfaces.nsIMsgAccountManager);
			var accounts = acctMgr.accounts;
			for (var i = 0; i < accounts.Count(); i++) {
				var account = accounts.QueryElementAt(i, Components.interfaces.nsIMsgAccount);
				var rootFolder = account.incomingServer.rootFolder; // nsIMsgFolder
				// set progress bar
				Application.console.log(rootFolder.prettiestName);
				var percentage = i/accounts.Count()*100;
				var accountName = rootFolder.prettiestName
				TheChasingDragon.process.setProgress(Math.round(percentage * 10) / 10+"% -"+stringBundlef.getString("cryptoBird.main.activitynextfolder")+rootFolder.prettiestName+"...", stringBundlef.getString("cryptoBird.main.activitynextfolder")+rootFolder.prettiestName, i, accounts.Count());
				// iterate the next folder (rootFolder)
				var result = this.iterateFolders(rootFolder, percentage, accountName);
				if (!result)
					break;
			}
			TheChasingDragon.process.state = Components.interfaces.nsIActivityProcess.STATE_COMPLETED;
			TheChasingDragon.gActivityManager.removeActivity(TheChasingDragon.process.id);
			// create event
			let event = Components.classes["@mozilla.org/activity-event;1"].createInstance(Components.interfaces.nsIActivityEvent);
			event.init(stringBundlef.getString("cryptoBird.main.activityfinishedindex"), null,stringBundlef.getString("cryptoBird.main.activityfinishedindex2"), TheChasingDragon.process.startTime, Date.now());
			TheChasingDragon.gActivityManager.addActivity(event);
		}
	};

	/*
	 *	Prompt for pgp-password for "user" (unused, but should replace Java prompt. If used, localization is needed)
	 */
	this.getPassword = function getPassword(user) {
		var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
		var password = {value: ""};              	
		var check = {value: true};                   		// default the checkbox to true
		var result = promptService.promptPassword(null, "PGP Password please...", "Enter PGP password for: "+user, password, null, check);
		if (result){ //result
			TheChasingDragon.cryptoBirdJava.addPassword(password.value);
		}
	};

	/**
	 *	SearchListener to get called when search (quickfilter) is done
	 *	implements nsIMsgSearchNotify
	 */
	this.searchListener = {
			onNewSearch :  function(){}, 		//alert("new search");
			onSearchDone : function(status)	{//alert("search done "+status);
				TheChasingDragon.searchTheChasingDragon();
			},
			onSearchHit : function(msgHdr, folder){} // alert("search hit:\n"+msgHdr.folder.getUriForMsg(msgHdr));
	};

	/**
	 *	Here starts the search.
	 *	XXX: Yet only local search. The global search has to be added here somewhere
	 */
	this.searchTheChasingDragon = function searchTheChasingDragon(){
		// get additional filters
		// TODO: need the label filter!
		// not async here. but ok i think
		var unread = document.getElementById("qfb-unread").checked;
		var starred = document.getElementById("qfb-starred").checked;
		var inaddrbook = document.getElementById("qfb-inaddrbook").checked;
		var attachment = document.getElementById("qfb-attachment").checked;
		var searchSubject = document.getElementById("qfb-qs-subject").checked;
		var searchBody = document.getElementById("qfb-qs-body").checked;

		// reset the search (remove all found messages)
		TheChasingDragon.list.clear();

		var new_search_value = document.getElementById("qfb-qs-textbox").value;
		// get search string from local search box

		new_search_value = new_search_value.replace(/^\s*([\S\s]*?)\s*$/, '$1');
		if (new_search_value.length > 0) {
			var foundMails = TheChasingDragon.cryptoBirdJava.getMailIdWhereFolder(new_search_value, gFolderDisplay.displayedFolder.baseMessageURI, searchBody, searchSubject);
			let messenger = Components.classes["@mozilla.org/messenger;1"].createInstance(Components.interfaces.nsIMessenger); 
			var count = new Object;
			for (k=0; k<foundMails.length; k=k+1){
				var foundMsgHdr = messenger.msgHdrFromURI(foundMails[k]);
				// check the additional filters
				var toShow = unread ? !foundMsgHdr.isRead : true;
				toShow &= starred ? foundMsgHdr.isFlagged : true;
				toShow &= inaddrbook ? authorKnown(foundMsgHdr.mime2DecodedAuthor) : true;
				toShow &= attachment ? ((foundMsgHdr.flags & 0x10000000) != 0) : true;

				// FIXME: first check if the message is not already in there!
				try {
					for (i=0; ;i=i+1){
						toShow &= (gDBView.getURIForViewIndex(i) != foundMails[k]);
					}
				} catch (e) {
				}
				if (toShow)
					TheChasingDragon.list.appendElement(foundMsgHdr, false);
			}
			if (foundMails.length > 0) {
				gDBView.openWithHdrs(TheChasingDragon.list.enumerate(), nsMsgViewSortType.byDate, nsMsgViewSortOrder.ascending, nsMsgViewFlagsType.kNone, new Object);
			}



		}
	};

	/**
	 *	Utility function: Checks whether the author is known to the Thunderbird
	 *	addressbook or not.
	 */
	function authorKnown(author){
		let enumerator = Components.classes["@mozilla.org/abmanager;1"].getService(Components.interfaces.nsIAbManager).directories;
		var found = "found";
		var mailAddi = author.match('<(.*)>')[1]; // TODO: don't know if this works every time!
		while (enumerator.hasMoreElements()) {
			let addrbook = enumerator.getNext();
			if (addrbook instanceof Components.interfaces.nsIAbDirectory && !addrbook.isRemote) {
				found = addrbook.cardForEmailAddress(mailAddi);
			}
		}
		return found != null;
	};

	/**
	 *	Get the body of a message, identified through aMessageHeader
	 */
	function getMessageBody(aMessageHeader) {
		let messenger = Components.classes["@mozilla.org/messenger;1"].createInstance(Components.interfaces.nsIMessenger);
		let listener = Components.classes["@mozilla.org/network/sync-stream-listener;1"].createInstance(Components.interfaces.nsISyncStreamListener);
		let uri = aMessageHeader.folder.getUriForMsg(aMessageHeader);
		messenger.messageServiceFromURI(uri).streamMessage(uri, listener, null, null, false, "");
		let folder = aMessageHeader.folder;
		var result = folder.getMsgTextFromStream(listener.inputStream,
				aMessageHeader.Charset,
				65536,
				32768,
				false,
				true,
				{ });
		return result;
	};

	/**
	 *	Get the Encoding of a message
	 */
	function getMailEncoding(aMessageHeader) {
		var encoding = aMessageHeader.Charset
		return encoding;
	};

	/**
	 *	cut the body of a message raw (pgp mime -> body from getMessageBody is not available)
	 */
	function getRawMessage(aMsgHdr, cutBody){
		var messenger = Components.classes["@mozilla.org/messenger;1"].createInstance(Components.interfaces.nsIMessenger);
		var uri = aMsgHdr.folder.getUriForMsg(aMsgHdr);
		var messageService = messenger.messageServiceFromURI(uri);
		var messageStream = Components.classes["@mozilla.org/network/sync-stream-listener;1"].createInstance().QueryInterface(Components.interfaces.nsIInputStream);
		var inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance().QueryInterface(Components.interfaces.nsIScriptableInputStream);
		inputStream.init(messageStream);
		messageService.streamMessage(uri, messageStream, {}, null, true, null);

		var body = "";
		inputStream.available();
		while (inputStream.available()) {
			body = body + inputStream.read(1024);
		}

		messageStream.close();
		inputStream.close(); 
		var result = cutBody(body, aMsgHdr);
		return result;
	};

	/**
	 *	Check if the body is a pgp mail and cut the pgp part out of it
	 */
	function cutPGPBody(body, aMsgHdr) {
		var endEncrypted = "-----END PGP MESSAGE-----";
		var startEncrypted = "-----BEGIN PGP MESSAGE-----";
		if (body.indexOf(startEncrypted) != -1 && body.indexOf(endEncrypted) != -1) {
			var result = body.substring(body.indexOf(startEncrypted)-startEncrypted.length, body.indexOf(endEncrypted)+endEncrypted.length+1);
			return result;
		}
	};

	/**
	 *	get body (and header) of a smime html mail
	 */
	this.coerceBodyToPlaintext = function coerceBodyToPlaintext(body, aMsgHdr) {
		var re = new RegExp('<html>'); //TODO: was is mit moz-text-flowed?
		var htmlPart = body.match(re);
		if (htmlPart) {
			return aMsgHdr.folder.convertMsgSnippetToPlainText(body);
		}
		return body;
	};

	/**
	 *	Check if the mail is a smime mail (do not need to cut anything here, TB gives me this message in plain)
	 */
	function cutSMIMEBody(body, aMsgHdr) {
		var smime = "pkcs7-mime"; //application/
		var xsmime = "x-pkcs7-mime"; // XXX: even more possibilities?! //application/
		MsgHdrToMimeMessage(aMsgHdr, null, function(aMsgHdr, aMimeMsg) {
			var type = aMimeMsg.parts.join("");
			if(type.indexOf("pkcs7") != -1){
				var parsed = TheChasingDragon.coerceBodyToPlaintext(body, aMsgHdr);
				TheChasingDragon.parse_smime_mail(parsed, aMsgHdr);
			}}, true, null);
	};

	/**
	 *	Add an S/MIME mail to the database (hand it over to Java).
	 *	TODO: Needs fix for too long mails (not occured yet)
	 */
	this.parse_smime_mail = function parse_smime_mail(decrypted, msgHdr){
		var maxLength = 8388608; // max length for string to give to Java
		var id = msgHdr.folder.getUriForMsg(msgHdr);
		if (decrypted.length < maxLength) {
			TheChasingDragon.cryptoBirdJava.addSmimeMail(id, decrypted, false, "", msgHdr.subject); //indexing & encoding is not used anymore!
		} else {
			// mail is too long to pass in one part to java -> split it FIXME: this is not really working, only dummy function!
			var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			prompt.alert(null, stringBundlef.getString("cryptoBird.main.smimeerror"),stringBundlef.getString("cryptoBird.main.smimemessage"));
			//		var part = decrypted.substring(0, maxLength);
			//		var startIndex = maxLength;
			//		TheChasingDragon.cryptoBirdJava.initMailParts(part, id); //FIXME: need other function here!
			//		while (part.length >= maxLength) {
			//			part = decrypted.substring(startIndex, startIndex+maxLength);
			//			TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, false); //FIXME: need other function here!
			//			startIndex = startIndex+maxLength;
			//		}
			//		part = decrypted.substring(startIndex, decrypted.length);
			//		TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, true); //FIXME: need other function here!
		}
	};

	/**
	 *	Parse and store encrypted mail in DB
	 */
	this.parse_encrypted_mail = function parse_encrypted_mail(msgHdr, indexing) {
		var result = true;
		var maxLength = 8388608; // max length for string to give to Java
		try {
			/*
			 * Check if message is in offline storage available or not
			 */
			if(msgHdr == null) alert("null!");
			if (msgHdr != null) { // offline?
				/*
				 *	Get Messagebody to decrypt
				 */
				var id = msgHdr.folder.getUriForMsg(msgHdr);
				var content = getMessageBody(msgHdr);
				var encoding = getMailEncoding(msgHdr);
				var pgpInline = "BEGIN PGP MESSAGE";

				// pgp mime or smime (no BEGIN PGP MESSAGE in there...)
				if (content.indexOf(pgpInline) == -1) {
					var encryptedContent = getRawMessage(msgHdr, cutPGPBody);

					// there is no pgp in there -> it must be a smime message (if it is encrypted)
					if (!encryptedContent) {
						decrypted = getRawMessage(msgHdr, cutSMIMEBody); // now using callback -> decrypted will never be set!
						if (decrypted) {
							if (decrypted.length < maxLength) {
								Application.console.log("-------- ID: "+id);
								result = TheChasingDragon.cryptoBirdJava.addSmimeMail(id, decrypted, indexing, encoding, msgHdr.subject); //ClearText
								result = true;
							} else { // mail is too long to pass in one part to java -> split it
								var part = decrypted.substring(0, maxLength);
								var startIndex = maxLength;
								TheChasingDragon.cryptoBirdJava.initMailParts(part, id); //FIXME: need other function here!
								while (part.length >= maxLength) {
									part = decrypted.substring(startIndex, startIndex+maxLength);
									TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, false, msgHdr.subject); //FIXME: need other function here!
									startIndex = startIndex+maxLength;
								}
								part = decrypted.substring(startIndex, decrypted.length);
								TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, true, msgHdr.subject); //FIXME: need other function here!
							}
						} else { //leere oder unverschl�sselte Mail:
							if (msgHdr.subject.indexOf("-----SUBJECT ENCRYPTED-----") > -1) { //nur in DB speichern, wenn subject verschl�sselt ist
								TheChasingDragon.cryptoBirdJava.initMailParts("", id);
								TheChasingDragon.cryptoBirdJava.addDecryptedMailPart("", true, msgHdr.subject);
							}
						}
					} else if (encryptedContent) { // if not: it has been a pgp message
						if (encryptedContent.length < maxLength) {
							Application.console.log("-------- ID: "+id);
							result = TheChasingDragon.cryptoBirdJava.saveDecryptedMail(id, encryptedContent, indexing, encoding, msgHdr.subject);
						} else { // mail is too long to pass in one part to java -> split it
							var part = encryptedContent.substring(0, maxLength);
							var startIndex = maxLength;
							TheChasingDragon.cryptoBirdJava.initMailParts(part, id);
							while (part.length >= maxLength) {
								part = encryptedContent.substring(startIndex, startIndex+maxLength);
								TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, false, msgHdr.subject);
								startIndex = startIndex+maxLength;
							}
							part = encryptedContent.substring(startIndex, encryptedContent.length);
							TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, true, msgHdr.subject);
						}
					}
				} else if (content.indexOf(pgpInline) != -1) { // inline pgp
					if (content.length < maxLength) {
						Application.console.log("-------- ID: "+id);
						result = TheChasingDragon.cryptoBirdJava.saveDecryptedMail(id, content, indexing, encoding, msgHdr.subject);
					} else { // mail is too long to pass in one part to java -> split it
						var part = content.substring(0, maxLength);
						var startIndex = maxLength;
						TheChasingDragon.cryptoBirdJava.initMailParts(part, id);
						while (part.length >= maxLength) {
							part = content.substring(startIndex, startIndex+maxLength);
							TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, false, msgHdr.subject);
							startIndex = startIndex+maxLength;
						}
						part = content.substring(startIndex, content.length);
						TheChasingDragon.cryptoBirdJava.addDecryptedMailPart(part, true, msgHdr.subject);
					}
				}
			}else{
				alert("!header ");
			} // end if != null
		} catch (e) {
			alert("**** (parse_encrypted_mail): "+e);
			dump(e+"\n");
		}
//		return result;
		return true;
	};
	
	// change unpack to false for TB-5 compliance -> addon does not work with TB3 any longer. should be done when TB5 is the commonly used version
	// -------------------------- DO NOT CHANGE ANYTHING BELOW ---------------------
	// ----------------------- unless you know what you are doin' ------------------
	this.startJava = function startJava(pgpPath, pgpSKName, pgpPKName, password){

		// add policies to run java from here
		function policyAdd (loader, urls) {
			try {
				//If have trouble with the policy try changing it to 
				//edu.mit.simile.javaFirefoxExtensionUtils.URLSetPolicy        
				var str = 'edu.mit.simile.javaFirefoxExtensionUtils.URLSetPolicy';
				var policyClass = java.lang.Class.forName(str, true, loader);
				var policy = policyClass.newInstance();
				policy.setOuterPolicy(java.security.Policy.getPolicy());
				java.security.Policy.setPolicy(policy);
				policy.addPermission(new java.security.AllPermission());
				for (var j=0; j < urls.length; j++) {
					policy.addURL(urls[j]);
				}
			}catch(e) {
				//alert(e+'::'+e.lineNumber);
			}
		};


		// Get path to the JAR files (the following assumes your JARs are within a
		// directory called "java" at the root of your extension's folder hierarchy)
		// You must add this utilities (classloader) JAR to give your extension full privileges
		var classLoaderJarpath = "file:///" + extensionPath.path.replace(/\\/g,"/") + "/content/javaFirefoxExtensionUtils.jar";
		// Add the paths for all the other JAR files that you will be using
		var urlArray = []; // Build a regular JavaScript array (LiveConnect will auto-convert to a Java array)
		try {
			urlArray[0] = new java.net.URL(classLoaderJarpath);
		} catch(e){
			var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			prompt.alert(null, stringBundlef.getString("cryptoBird.main.warning"), ""+e+"\n" +stringBundlef.getString("cryptoBird.main.enablejava"));
			throw e;
		}
		// generate these with getJars.sh
		urlArray[1] = new java.net.URL("file:///" + extensionPath.path.replace(/\\/g,"/") + "/content/CryptoBird_lib/bcpg-jdk16-146.jar");
		urlArray[2] = new java.net.URL("file:///" + extensionPath.path.replace(/\\/g,"/") + "/content/CryptoBird_lib/bcprov-jdk16-146.jar");
		urlArray[3] = new java.net.URL("file:///" + extensionPath.path.replace(/\\/g,"/") + "/content/CryptoBird_lib/derby.jar");
		urlArray[4] = new java.net.URL("file:///" + extensionPath.path.replace(/\\/g,"/") + "/content/CryptoBird.jar");

		//Set security policies using the above policyAdd() function
		var cl = java.net.URLClassLoader.newInstance(urlArray);
		policyAdd(cl, urlArray);
		var myClass = cl.loadClass('de.tud.cdc.CryptoBird'); // use the same loader from above
		TheChasingDragon.cryptoBirdJava = myClass.newInstance();

		// get profile path to store db there
		var profilePath =	Components.classes["@mozilla.org/file/directory_service;1"].
		getService(Components.interfaces.nsIProperties).
		get("ProfD", Components.interfaces.nsIFile);


		// set properties
		var initResult = TheChasingDragon.cryptoBirdJava.initialize(pgpPath, pgpSKName, pgpPKName, password, profilePath.path.replace(/\\/g,"/")+"/cryptoBird/mailDB");
		var cnt = 0;
		while (initResult != "" && cnt < 3 && initResult != "Can't find the GPG secret keyring. Please edit the path and restart if you use GPG encrypted emails.") {
			var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			prompt.alert(null, stringBundlef.getString("cryptoBird.main.warning"), initResult);
			var newPWD, results;
			if (initResult.indexOf("in use") != -1) {
				initResult = TheChasingDragon.cryptoBirdJava.initialize(pgpPath, pgpSKName, pgpPKName, password, profilePath.path.replace(/\\/g,"/")+"/cryptoBird/mailDB");
				results = stringBundlef.getString("cryptoBird.main.dBinuse");
				break;
			} else if (initResult.indexOf("password") != -1) {
				newPWD = TheChasingDragon.getPWD();
				results = stringBundlef.getString("cryptoBird.main.threetimesdisabled");
			} else if (initResult.indexOf("keyring") != -1) {
				results = stringBundlef.getString("cryptoBird.main.disabled");
				break;
			}
			initResult = TheChasingDragon.cryptoBirdJava.initialize(pgpPath, pgpSKName, pgpPKName, newPWD.value, profilePath.path.replace(/\\/g,"/")+"/cryptoBird/mailDB");
			++cnt;
		}
		if (initResult != "" && initResult != "Can't find the GPG secret keyring. Please edit the path and restart if you use GPG encrypted emails.") {
			var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
			prompt.alert(null, stringBundlef.getString("cryptoBird.main.warning"), results);
			this.disabled = true;
		}

		/*
		 *	Warn user that no pgp is available.
		 */
		var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("cryptoBird.");
		var warn_pgp = prefs.getBoolPref("pgp_warning");
		if (initResult == "Can't find the GPG secret keyring. Please edit the path and restart if you use GPG encrypted emails." && warn_pgp){
			if (firstRun("cryptoBird", false)) { // TODO: this avoids false warning at first start. has to be fixed correctly
				var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
				var check = {value: false};
				prompt.alertCheck(null, "Warning", stringBundlef.getString("cryptoBird.main.keyringnotfound"), stringBundlef.getString("cryptoBird.main.nottellagain"), check);
				// safe it in preferences
				// prefs is an nsIPrefBranch.
				prefs.setBoolPref("pgp_warning", !check.value);
			}
		}
	};

} // end cryptoBird class

/*============================================================================*/
/* Preferences                                                                */
/*============================================================================*/

//Get a string preference value. This function silently returns with an empty
//string if the specified preference does not exist.
function safeGetCharPref (prefBranch, prefName) {
	if (prefBranch == null || prefName == null || prefName == "")
		return "";

	// We need to check whether the specified entry exists at all
	var cntContainer = new Object ();
	var entries = prefBranch.getChildList ("", cntContainer);
	for (i = 0; i < cntContainer.value; i++)
		if (entries [i] == prefName)
			return prefBranch.getCharPref (prefName);
	return "";
}

//Encoding utility functions
function getSMIMEEncoding(doc){
	var re = new RegExp(/<div class="moz-text-(plain|html)"(.*)lang="(.*)">/);
	var textDiv = doc.match(re);
	if (textDiv)
		return textDiv[3];
}

function getPGPEncoding(doc){
	// Content-Type: text/plain; charset=ISO-8859-1
	var re = new RegExp(/Content-Type: text\/(plain|html); charset=(.*)/);
	var textDiv = doc.match(re);
	if (textDiv)
		return textDiv[2];
}

function myDump(aMessage) {
	var consoleService = Components.classes["@mozilla.org/consoleservice;1"]
	.getService(Components.interfaces.nsIConsoleService);
	consoleService.logStringMessage("CryptoBird: " + aMessage);
}
